package com.baigt.juc.base.volatile_;

import java.util.concurrent.CountDownLatch;

/**
 * 类功能描述:
 * 示例多线程变量修改 其他线程无法感知到变化
 * 原子性(不支持)  下边为不保证原子性的示例
 * 可见性
 * 有序性
 （1）使用上的区别
    volatile关键字只能用于修饰实例变量或者类变量，不能用于修饰方法以及方法参数和局部变量、常量等。
    synchronized关键字不能用于对变量的修饰，只能用于修饰方法或者语句块。
    volatile修饰的变量可以为nul，synchronized关键字同步语句块的 monitor对象不能为nul
 （2）对原子性的保证
     volatile无法保证原子性。
     由于 synchronized是一种排他的机制，因此被 synchronized关键字修饰的同步代码是无法被中途打断的，因此其能够保证代码的原子性。
 （3）对可见性的保证
     口两者均可以保证共享资源在多线程间的可见性，但是实现机制完全不同。
     synchronized借助于JVM指令 monitor enter和 monitor exit对通过排他的方式使得同步代码串行化，在 monitor exit时所有共享资源都将会被刷新到主内存中。
     口相比较于 synchronized关键字 volatile使用机器指令（偏硬件）“lock;”的方式迫使其他线程工作内存中的数据失效，不得到主内存中进行再次加载。
 （4）对有序性的保证
     口 volatile关键字禁止JVM编译器以及处理器对其进行重排序，所以它能够保证有序性。
     口虽然 synchronized关键字所修饰的同步方法也可以保证顺序性，但是这种顺序性是以程序的串行化执行换来的，在 synchronized关键字所修饰的代码块中代码指令也会发生指令重排序的情况，比如：
     synchronized（this）{
         int x =10;
         int y =20;
         x++;
         y=y+1;
     }
    x和y谁最先定义以及谁最先进行运算，对程序来说没有任何的影响，另外x和y之间也没有依赖关系，但是由于 synchronized关键字同步的作用，在 synchronized的作用域结束时ⅹ必定是11，y必定是21，
    也就是说达到了最终的输出结果和代码编写顺序的一致性。
 （5）其他
    volatile不会使线程陷入阻塞。
    口 synchronized关键字会使线程进人阻塞状态。
 * @author baigt
 * @version V1.0
 * @since 2019-10-24 17:54
 */
public class VolatileDemo02 {

    //初始变量
    static volatile int initvalue = 0;

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch=new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    initvalue++;
                }
                latch.countDown();
            }, "write-"+i).start();
        }
        latch.await();
        System.out.println(initvalue);
    }
}
